﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;

namespace NDF.Web.Mvc.UI.EasyUI
{
    public class EasyUiBuilder : UiBuilder
    {
        public EasyUiType Type { get; set; }

        public string Name { get; set; }

        public object Value { get; set; }

        public bool SetId { get; set; }

        public string InnerHtml { get; set; }

        /// <summary>
        /// 获取或设置生成的 html-UI 控件的初始化选项属性值或属性集合。
        /// 该属性值的数据类型可以为：
        ///     object(建议为匿名类直接定义各属性，属性名表示初始化选项名，属性值表示初始化选项的值，属性值可以定义为 string|int 类型。)、
        ///     或 IDictionary<string, object> 类型其中 string 值表示初始化选项名，object 值表示初始化选项的值可以为 string|int。
        /// </summary>
        public object HtmlAttributes { get; set; }

        /// <summary>
        /// 获取或设置生成的 EasyUI 控件的初始化选项属性值或属性集合。
        /// 该属性值的数据类型可以为：
        ///     object(建议为匿名类直接定义各属性，属性名表示初始化选项名，属性值表示初始化选项的值，属性值可以定义为 string|int 类型。)、
        ///     或 string 类型表示一个可以用于定义 data-options 的字符串、
        ///     或 IDictionary<string, object> 类型其中 string 值表示初始化选项名，object 值表示初始化选项的值可以为 string|int。
        /// </summary>
        public object DataOptions { get; set; }


        public string OptionsToken
        {
            get { return "data-options"; }
        }

        public string ValueToken
        {
            get { return "value"; }
        }



        protected internal virtual TagBuilder GetTagBuilder()
        {
            string tagName = this.Type.GetTagName(),
                fullName = this.Name,
                easyuiClass = this.Type.GetHtmlClass();
            bool isFormControl = this.Type.IsFormControl(),
                valueToInnerHtml = this.Type.ValueToInnerHtml();
            var defaultClass = this.Type.GetDefaultClass();

            var tagBuilder = new TagBuilder(tagName);
            var htmlAttributs = ToHtmlAttributes(this.HtmlAttributes);
            if (this.SetId)
            {
                tagBuilder.GenerateId(fullName);
            }
            tagBuilder.MergeAttributes(htmlAttributs, true);

            tagBuilder.AddCssClass(defaultClass, true);
            tagBuilder.AddCssClass(easyuiClass, true);

            string dataOptions = null,
                options = this.GetOptionsString();
            if (tagBuilder.Attributes.TryGetValue(this.OptionsToken, out dataOptions) && !string.IsNullOrWhiteSpace(dataOptions))
            {
                options = string.IsNullOrWhiteSpace(dataOptions) ? options : (dataOptions + (dataOptions.Trim().EndsWith(",") ? "" : ", ") + options);
            }

            var value = this.Value;
            string innerHtml = this.InnerHtml;
            if (valueToInnerHtml)
            {
                innerHtml = Convert.ToString(value);
                value = null;
            }
            if (value != null)
            {
                tagBuilder.MergeAttribute(this.ValueToken, value.ToString());
                string valueSpan = string.Format("{0}: {1}", this.ValueToken, this.ValueToString(value));
                options = string.IsNullOrWhiteSpace(options) ? valueSpan : (options + (options.Trim().EndsWith(",") ? "" : ", ") + valueSpan);
                tagBuilder.MergeAttribute(this.ValueToken, value is string ? value as string : this.ValueToString(value));
            }
            if (!string.IsNullOrWhiteSpace(options))
            {
                tagBuilder.MergeAttribute(this.OptionsToken, options);
            }
            
            if (tagName.Equals("input", StringComparison.CurrentCultureIgnoreCase))
            {
                tagBuilder.MergeAttribute("type", this.Type.GetInputType());
            }
            tagBuilder.MergeAttribute("name", fullName, true);
            if (innerHtml != null && innerHtml.Length > 0)
            {
                tagBuilder.InnerHtml = HttpUtility.HtmlDecode(innerHtml);
            }
            return tagBuilder;
        }




        protected internal virtual string GetOptionsString()
        {
            if (this.DataOptions == null) { return string.Empty; }
            if (this.DataOptions is string) { return this.DataOptions as string; }
            StringBuilder stringBuinder = new StringBuilder();
            var opts = ToHtmlAttributes(this.DataOptions);
            foreach (var item in opts)
            {
                if (stringBuinder.Length > 0)
                {
                    stringBuinder.Append(", ");
                }
                stringBuinder.AppendFormat("{0}: {1}", item.Key, this.ValueToString(item.Value));
            }
            return stringBuinder.ToString();
        }

        protected internal virtual string ValueToString(object value)
        {
            if (value == null) { return null; }
            if (value is IJsonString) { return ((IJsonString)value).ToJsonString(); }
            var ret = value is string && ((string)value).IsJavaScriptFunction() ? value.ToString() : Json.Encode(value);
            if (ret.StartsWith("\"") && ret.EndsWith("\"") && ret.Length >= 2)
            {
                ret = "'" + ret.Substring(1, ret.Length - 2) + "'";
            }
            return ret;
        }

        protected internal static IDictionary<string, object> ToHtmlAttributes(object htmlAttributes)
        {
            return htmlAttributes is IDictionary<string, object> ? htmlAttributes as IDictionary<string, object>
                : HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
        }
    }
}
